<?php

/*
Copyright 2009-2011 Sam Weiss
All Rights Reserved.

This file is part of Spark/Plug.

Spark/Plug is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

if (!defined('spark/plug'))
{
	header('HTTP/1.1 403 Forbidden');
	exit('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><html><head><title>403 Forbidden</title></head><body><h1>Forbidden</h1><p>You don\'t have permission to access the requested resource on this server.</p></body></html>');
}

//------------------------------------------------------------------------------

class SparkCRUDController extends SparkController
{
	protected $model;
	protected $modelName;
	protected $resourceName;
	protected $resourcePluralName;

	//---------------------------------------------------------------------------

	public function __construct($modelName, $params = NULL)
	{		
		parent::__construct();

		$this->modelName = $modelName;
		
		if (!empty($params['resource_name']))
		{
			$this->resourceName = $params['resource_name'];
		}
		if (!empty($params['resource_plural_name']))
		{
			$this->resourcePluralName = $params['resource_plural_name'];
		}

		if (empty($this->resourcePluralName))
		{
			$this->resourcePluralName = !empty($this->resourceName) ? $this->resourceName . 's' : strtolower($modelName);
		}
		if (empty($this->resourceName))
		{
			$this->resourceName = substr($this->resourcePluralName, 0, -1);
		}
	}
	
	//---------------------------------------------------------------------------

	public function _before_dispatch($method, $params)
	{
		$this->model = $this->newModel($this->modelName, $params);
		return true;
	}

	//---------------------------------------------------------------------------

	public function action_index($params)
	{
		try
		{
			$result = $this->model->findByFilter($params['qv']);
		}
		catch (SparkCRUDException_NotFound $e)
		{
			throw new SparkHTTPException_NotFound(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_Authorization $e)
		{
			throw new SparkHTTPException_Unauthorized(NULL, array('reason'=>$e->getMessage()));
		}

		$this->response($params, array($this->resourcePluralName=>$result), '200', $this->resourcePluralName);
	}

	//---------------------------------------------------------------------------

	public function action_create($params)
	{
		try
		{
			$result = $this->model->create($params['pv'], $params['request']);
		}
		catch (SparkCRUDException_Authorization $e)
		{
			throw new SparkHTTPException_Unauthorized(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_Conflict $e)
		{
			throw new SparkHTTPException_Conflict(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_Validation $e)
		{
			throw new SparkHTTPException_BadRequest(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_Quota $e)
		{
			throw new SparkHTTPException_Forbidden(NULL, array('reason'=>$e->getMessage()));
		}

		$headers['Location'] = $this->getResourceURI($params['pv']);
		$this->response($params, array($this->resourceName=>$result), '201', $this->resourceName, $headers);
	}

	//---------------------------------------------------------------------------

	public function action_clear($params)
	{
		try
		{
			$this->model->deleteAll();
		}
		catch (SparkCRUDException_Authorization $e)
		{
			throw new SparkHTTPException_Unauthorized(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_Validation $e)
		{
			throw new SparkHTTPException_BadRequest(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_NotFound $e)
		{
			throw new SparkHTTPException_NotFound(NULL, array('reason'=>$e->getMessage()));
		}

		$this->response($params, NULL, '200', $this->resourceName);
	}

	//---------------------------------------------------------------------------

	public function action_show($params)
	{
		if (!$resourceID = @$params['id'])
		{
			throw new SparkHTTPException_NotFound(NULL, array('reason'=>"{$this->resourceName} not found"));
		}
		
		try
		{
			$result = $this->model->findByID($resourceID, @$params['rv']['property']);
		}
		catch (SparkCRUDException_Authorization $e)
		{
			throw new SparkHTTPException_Unauthorized(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_NotFound $e)
		{
			throw new SparkHTTPException_NotFound(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_Validation $e)
		{
			throw new SparkHTTPException_BadRequest(NULL, array('reason'=>$e->getMessage()));
		}

		$this->response($params, array($this->resourceName=>$result), '200', $this->resourceName);
	}

	//---------------------------------------------------------------------------

	public function action_update($params)
	{
		if (!$resourceID = @$params['id'])
		{
			throw new SparkHTTPException_NotFound(NULL, array('reason'=>"{$this->resourceName} not found"));
		}

		try
		{
			$this->model->update($resourceID, $params['pv'], $params['request']);
		}
		catch (SparkCRUDException_Authorization $e)
		{
			throw new SparkHTTPException_Unauthorized(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_NotFound $e)
		{
			throw new SparkHTTPException_NotFound(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_Conflict $e)
		{
			throw new SparkHTTPException_Conflict(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_Validation $e)
		{
			throw new SparkHTTPException_BadRequest(NULL, array('reason'=>$e->getMessage()));
		}

		$this->response($params, NULL, '200', $this->resourceName);
	}

	//---------------------------------------------------------------------------

	public function action_destroy($params)
	{
		if (!$resourceID = @$params['id'])
		{
			throw new SparkHTTPException_NotFound(NULL, array('reason'=>"{$this->resourceName} not found"));
		}

		try
		{
			$this->model->deleteByID($resourceID);
		}
		catch (SparkCRUDException_Authorization $e)
		{
			throw new SparkHTTPException_Unauthorized(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_Validation $e)
		{
			throw new SparkHTTPException_BadRequest(NULL, array('reason'=>$e->getMessage()));
		}
		catch (SparkCRUDException_NotFound $e)
		{
			throw new SparkHTTPException_NotFound(NULL, array('reason'=>$e->getMessage()));
		}

		$this->response($params, NULL, '200', $this->resourceName);
	}

	//---------------------------------------------------------------------------

	protected function response($params, $response, $status, $view = NULL, $headers = NULL)
	{
		$contentType = $params['http-accept'][0];
		$output = $this->encodeResponseData($response, $contentType);
		$this->display($output, $contentType, $status, $headers);
	}
	
	//---------------------------------------------------------------------------

	protected function getResourceName()
	{
		throw new SparkHTTPException_InternalServerError(NULL, array('reason'=>'controller method "getResourceName" not implemented'));
	}
	
	//---------------------------------------------------------------------------

	protected function getResourceURI($resource)
	{
		throw new SparkHTTPException_InternalServerError(NULL, array('reason'=>'controller method "getResourceURI" not implemented'));
	}
	
	//---------------------------------------------------------------------------
	
}
